package no.hig.imt4721.presentation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import no.hig.imt4721.matching.Matcher;
import no.hig.imt4721.model.DataPoint;

public class Presentation
{
	private Matcher matcher = null;

	List<DataPoint> dataPoints = null;
	
	public Presentation(Matcher matcher)
	{
		this.matcher = matcher;
	}

	
	public double getEER()
	{
		if(dataPoints == null)
			dataPoints = getDataPoints();
		
		for(int i = 0; i < dataPoints.size() - 1; i++)
		{
			DataPoint currentPoint = dataPoints.get(i);
			DataPoint nextPoint = dataPoints.get(i+1);
			
			if(currentPoint.getFNMR() > currentPoint.getFMR() && nextPoint.getFNMR() < nextPoint.getFMR())
				return (currentPoint.getFMR() + currentPoint.getFNMR() + nextPoint.getFMR() + nextPoint.getFNMR()) / 4D;
			
			if(currentPoint.getFNMR() == currentPoint.getFMR())
				return currentPoint.getFNMR();
		}
		
		return 0;
	}

	public List<DataPoint> getDataPoints()
	{
		if(dataPoints == null)
		{
			List<Double> genuineScores = matcher.getGenuineScores();
			List<Double> impostorScores = matcher.getImpostorScores();
			List<Double> allScores = new ArrayList<Double>();
			allScores.addAll(genuineScores);
			allScores.addAll(impostorScores);

			//System.out.println("Sorting scores started.");
			Collections.sort(genuineScores);
			Collections.sort(impostorScores);
			Collections.sort(allScores);
			//System.out.println("Sorting scores stopped.");
			
			//System.out.println("Calculating MatchRates started.");

			dataPoints = calculateMatchRates(allScores, genuineScores, impostorScores);
			
			//System.out.println("Calculating MatchRates stopped.");
		}
		
		return dataPoints;
	}
	
	private List<DataPoint> calculateMatchRates(List<Double> allScores, List<Double> genuineScores, List<Double> impostorScores)
	{
		List<DataPoint> dataPoints = new ArrayList<DataPoint>();
		
		int lastIndexGenuineScores = 0;
		int lastIndexImpostorScores = impostorScores.size() - 1;
		
		for(int i = 0; i < allScores.size(); i++)
		{
			double t = 0;
			double score = allScores.get(i);
			
			if(i == 0)
				t = score - 1;
			else if(i == allScores.size() - 1)
				t = score + 1;
			else
				t = 0.5 * (score + allScores.get(i+1));
			
			
			int nrGenuineAboveThreshold = 0;
			int nrImpostorBelowThreshold = 0;
			
			for(int j = lastIndexGenuineScores; j < genuineScores.size(); j++)
			{
				if(genuineScores.get(j) > t)
				{
					nrGenuineAboveThreshold = genuineScores.size() - j;
					lastIndexGenuineScores = j;
					break;
				}
			}
			
			for(int j = lastIndexImpostorScores; j >= 0; j--)
			{
				if(impostorScores.get(j) <= t)
				{
					nrImpostorBelowThreshold = j + 1;
					lastIndexImpostorScores = ((j+1) >= (impostorScores.size() - 1)) ? (impostorScores.size() - 1) : (j + 1);
					break;
				}
			}
			
			dataPoints.add(new DataPoint(nrGenuineAboveThreshold / matcher.getGEN(), nrImpostorBelowThreshold / matcher.getIMP()));
			
			//if(i % 100 == 0)
			//	System.out.println("Progress: " + i +" of " + allScores.size() + " thresholds processed");
		}
		
		return dataPoints;
	}
		
}